package com.gdyx.bc.gw.web;

import com.gdyx.bc.gw.sdk.unionpay.AcpService;
import com.gdyx.bc.gw.sdk.unionpay.LogUtil;
import com.gdyx.bc.gw.sdk.unionpay.SDKConfig;
import com.gdyx.bc.gw.sdk.unionpay.SDKConstants;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by mac on 2017/5/13.
 */
@Controller
@RequestMapping("/BindCard")
public class BindCardController {
    @RequestMapping(value = "/OpenToken")
    @ResponseBody
    public String OpenToken(String certifTp, String certifId, String customerNm, String phoneNo, String accNo){
        String merId = "777290083980019";
        String orderId = "GDYXBC" + System.currentTimeMillis();
        String txnTime = new SimpleDateFormat("yyyyMMddhhmmss").format(new Date());
        String backUrl = "http://donkeycanfly.xicp.net:9089/BindCard/CallBack";
        String frontUrl = "";
        Map<String, String> contentData = new HashMap<String, String>();
        /***银联全渠道系统，产品参数，除了encoding自行选择外其他不需修改***/
        contentData.put("version", "5.0.0");     			//版本号
        contentData.put("encoding", "UTF-8");            				//字符集编码 可以使用UTF-8,GBK两种方式
        contentData.put("signMethod", SDKConfig.getConfig().getSignMethod());   //签名方法
        contentData.put("txnType", "79");                              			//交易类型 11-代收
        contentData.put("txnSubType", "00");                           			//交易子类型 00-默认开通
        contentData.put("bizType", "000902");                          			//业务类型 Token支付
        contentData.put("channelType", "08");                          			//渠道类型08-手机
        /***商户接入参数***/
        contentData.put("merId", merId);                   			   //商户号码（本商户号码仅做为测试调通交易使用，该商户号配置了需要对敏感信息加密）测试时请改成自己申请的商户号，【自己注册的测试777开头的商户号不支持代收产品】
        contentData.put("accessType", "0");                            //接入类型，商户接入固定填0，不需修改
        contentData.put("orderId", orderId);             			   //商户订单号，8-40位数字字母，不能含“-”或“_”，可以自行定制规则
        contentData.put("txnTime", txnTime);         				   //订单发送时间，格式为YYYYMMDDhhmmss，必须取当前时间，否则会报txnTime无效
        contentData.put("accType", "01");                              //账号类型
        contentData.put("tokenPayData", "{trId=62000000001&tokenType=01}");
        //选送卡号、手机号、证件类型+证件号、姓名
        //也可以都不送,在界面输入这些要素
        Map<String,String> customerInfoMap = new HashMap<String,String>();
        customerInfoMap.put("certifTp", certifTp);						//证件类型
        customerInfoMap.put("certifId", certifId);		//证件号码
        customerInfoMap.put("customerNm", customerNm);					//姓名
        customerInfoMap.put("phoneNo", phoneNo);			    //手机号
        ////////////如果商户号开通了【商户对敏感信息加密】的权限那么需要对 accNo和phoneNo加密（如果报文上送），对敏感信息加密使用：
        //String accNo = AcpService.encryptData("6216261000000002485", DemoBase.encoding);  //这里测试的时候使用的是测试卡号，正式环境请使用真实卡号
        //contentData.put("accNo", accNo);
        //contentData.put("encryptCertId",AcpService.getEncryptCertId());       //加密证书的certId，配置在acp_sdk.properties文件 acpsdk.encryptCert.path属性下
        //String customerInfoStr = AcpService.getCustomerInfoWithEncrypt(customerInfoMap,null,DemoBase.encoding);
        //////////

        /////////如果商户号未开通【商户对敏感信息加密】权限那么不需对敏感信息加密使用：
        contentData.put("accNo", accNo);
        String customerInfoStr = AcpService.getCustomerInfo(customerInfoMap,null,"UTF-8");   //前台实名认证送支付验证要素 customerInfo中要素不要加密
        contentData.put("customerInfo", customerInfoStr);
        contentData.put("frontUrl", frontUrl);
        contentData.put("backUrl", backUrl);
        contentData.put("reserved", "{customPage=true}");         	//如果开通页面需要使用嵌入页面的话，请上送此用法
        // 超过超时时间调查询接口应答origRespCode不是A6或者00的就可以判断为失败。
        contentData.put("payTimeout", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date().getTime() + 15 * 60 * 1000));
        /**请求参数设置完毕，以下对请求参数进行签名并生成html表单，将表单写入浏览器跳转打开银联页面**/
        Map<String, String> reqData = AcpService.signByCertInfo(contentData,"/Users/mac/certs/acp_test_sign.pfx","000000","UTF-8");  			 //报文中certId,signature的值是在signData方法中获取并自动赋值的，只要证书配置正确即可。
        String requestFrontUrl = SDKConfig.getConfig().getFrontRequestUrl();    						 //获取请求银联的前台地址：对应属性文件acp_sdk.properties文件中的acpsdk.frontTransUrl
        String html = AcpService.createAutoFormHtml(requestFrontUrl,reqData,"UTF-8");     //生成自动跳转的Html表单

        LogUtil.writeLog("打印请求HTML，此为请求报文，为联调排查问题的依据："+html);
        //resp.getWriter().write(html);
        // 将生成的html写到浏览器中完成自动跳转打开银联支付页面；这里调用signData之后，
        // 将html写到浏览器跳转到银联页面之前均不能对html中的表单项的名称和值进行修改，如果修改会导致验签不通过
        return html;
    }
    @RequestMapping(value = "/CallBack")
    @ResponseBody
    public String CallBack(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        System.out.println("接收到银联后台通知");
        String encoding = request.getParameter(SDKConstants.param_encoding);
        // 获取银联通知服务器发送的后台通知参数
        Map<String, String> reqParam = getAllRequestParam(request);
        Map<String, String> valideData = null;
        if (null != reqParam && !reqParam.isEmpty()) {
            Iterator<Map.Entry<String, String>> it = reqParam.entrySet().iterator();
            valideData = new HashMap<>(reqParam.size());
            while (it.hasNext()) {
                Map.Entry<String, String> e = it.next();
                String key = (String) e.getKey();
                String value = (String) e.getValue();
                value = new String(value.getBytes(encoding), encoding);
                valideData.put(key, value);
            }
        }

        //重要！验证签名前不要修改reqParam中的键值对的内容，否则会验签不过
        if (!AcpService.validate(valideData, encoding)) {
            //验签失败，需解决验签问题

        } else {
            //【注：为了安全验签成功才应该写商户的成功处理逻辑】交易成功，更新商户订单状态
            Iterator<Map.Entry<String, String>> it = valideData.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, String> en = it.next();
                System.out.println(String.format("key=%s,value=%s", en.getKey(), en.getValue()));
            }
        }
        //返回给银联服务器http 200  状态码
        return "Ok";
    }

    public Map<String, String> getAllRequestParam(HttpServletRequest request) {
        Map<String, String> res = new HashMap<>();
        Enumeration<?> temp = request.getParameterNames();
        if (null != temp) {
            while (temp.hasMoreElements()) {
                String en = (String) temp.nextElement();
                String value = request.getParameter(en);
                res.put(en, value);
                if (null == res.get(en) || "".equals(res.get(en))) {
                    res.remove(en);
                }
            }
        }
        return res;
    }

}
